/**
 * This file is released under the GNU General Public License.
 * Refer to the COPYING file distributed with this package.
 *
 * Copyright (c) 2008-2009 WURFL-Pro srl
 */
package net.sourceforge.wurfl.core;

import net.sourceforge.wurfl.core.resource.ModelDevice;
import net.sourceforge.wurfl.core.resource.WURFLModel;

import org.apache.commons.lang.Validate;
import org.apache.commons.lang.text.StrBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * DeviceProvider default implementation.
 * <p>
 * It create DefaultDevices using the CapabilitiesHolderFactory and
 * MarkupResolver. By default it uses DefaultCapabilitiesHolderFactory and
 * DefaultMarkupResolver. Several constructors permit to customize the building
 * procedure.
 * </p>
 * 
 * @author WURFL-PRO SRL, Rome, Italy
 * @version $Id: DefaultDeviceProvider.java 1045 2009-03-09 15:52:53Z filippo.deluca $
 */
public class DefaultDeviceProvider extends AbstractDeviceProvider {
	
	/** Log */
	private static final Log log = LogFactory.getLog(DefaultDeviceProvider.class);

	/** The MarkupResolver used to initialize DefaultDevice */
	private final MarkupResolver markupResolver;

	/** The CapabilitiesHolderFactory used to obtain CapabilitiesHolder */
	private final CapabilitiesHolderFactory capabilitiesHolderFactory;

	// Constructors *******************************************************

	/**
	 * Create DefaultDeviceProvider by WURFLModel, CapabilitiesHolderFactory and
	 * MarkupResolver.
	 * 
	 * @param model
	 *            The WURFLModel used to obtain the root {@link ModelDevice}.
	 * @param capabilitiesHolderFactory
	 *            The CapabilitiesHolderFactory used to create
	 *            CapabilitiesHolder for the devices.
	 * @param markupResolver
	 *            The MarkupResolver used to initialize new devices.
	 */
	public DefaultDeviceProvider(WURFLModel model,
			CapabilitiesHolderFactory capabilitiesHolderFactory,
			MarkupResolver markupResolver) {

		super(model);

		Validate.notNull(capabilitiesHolderFactory,
				"capabilitiesHolderFactory must be not null.");
		Validate.notNull(markupResolver, "markupResolver must be not null.");

		this.capabilitiesHolderFactory = capabilitiesHolderFactory;
		this.markupResolver = markupResolver;
	}

	/**
	 * Create DefaultDeviceProvider by WURFLModel and MarkupResolver.
	 * <p>
	 * It uses DefaultMarkupResolver as MarkupResolver implementation.
	 * </p>
	 * 
	 * @param model
	 *            The {@link WURFLModel} used to obtain the root
	 *            {@link ModelDevice}.
	 * @param markupResolver
	 *            The {@link MarkupResolver} used to initialize new devices.
	 */
	public DefaultDeviceProvider(WURFLModel model,
			CapabilitiesHolderFactory capabilitiesHolderFactory) {

		this(model, capabilitiesHolderFactory, new DefaultMarkupResolver());
	}

	/**
	 * Create DefaultDeviceProvider by WURFLModel and MarkupResolver.
	 * 
	 * <p>
	 * It uses DefaultCapabilitiesHolderFactory as CapabilitiesHolderFactory
	 * implementation.
	 * </p>
	 * 
	 * @param model
	 *            The {@link WURFLModel} used to obtain the root
	 *            {@link ModelDevice}.
	 * @param markupResolver
	 *            The {@link MarkupResolver} used to initialize new devices.
	 */
	public DefaultDeviceProvider(WURFLModel model, MarkupResolver markupResolver) {

		this(model, new DefaultCapabilitiesHolderFactory(model), markupResolver);
	}

	/**
	 * Create DefaultDeviceProvider by WURFLModel.
	 * 
	 * <p>
	 * It uses DefaultMarkupResolver as MarkupResolver implementation and
	 * DefaultCapabilitiesHolderFactory as CapabilitiesHolderFactory
	 * implementation.
	 * </p>
	 * 
	 * @param model
	 *            The WURFLModel used to obtain the root ModelDevice.
	 */
	public DefaultDeviceProvider(WURFLModel model) {
		this(model, new DefaultCapabilitiesHolderFactory(model),
				new DefaultMarkupResolver());
	}

	// Business methods ***************************************************

	/**
	 * {@inheritDoc}
	 */
	public Device getDevice(String id) throws DeviceNotDefinedException {

		Validate.notEmpty(id, "The id must be not null String");

		// Load modelDevice
		ModelDevice modelDevice = getModelDevice(id);

		// Create Device
		assert modelDevice != null : "modelDevice is null";

		CapabilitiesHolder capabilityHolder = createCapabilitiesHolder(modelDevice);

		Device device = new DefaultDevice(modelDevice, capabilityHolder,
				markupResolver);

		if (log.isTraceEnabled()) {
			StrBuilder logBuilder = new StrBuilder();
			logBuilder.append("Return device: ").append(device);

			log.trace(logBuilder.toString());
		}

		return device;

	}

	// support methods ****************************************************

	/**
	 * Factory method to build CapabilityHolder instances.
	 * 
	 * @param modelDevice
	 *            The ModelDevices root of the creating device.
	 */
	protected CapabilitiesHolder createCapabilitiesHolder(
			ModelDevice modelDevice) {

		return capabilitiesHolderFactory.create(modelDevice);
	}

}
